home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
051-075
/
scopedisk62
/
mfr
/
midiclock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
7KB
|
252 lines
/* MIDICLOCK, Pete Yadlowsky, 3/89
This program is based loosely on a simple CIA timer application
originally written by Paul Higginbotham (sp?) and placed in the
public domain. Thanks, Paul.
The function of this program is to provide a time counter that
any task may access, usually for the purpose of calculating
time elapsed between events. This program was written to
facilitate the recording of MIDI events and to allow several
MIDI processes to share a common timebase, but is general enough
to be useful in a wide range of applications.
The program sets up a CIA timer interrupt in order to produce
a number of 'ticks' per second (specified on command line or
in message), and to simply count these ticks. The current
tick count, along with the current rate (actually, microseconds
per tick), is stored in a simple structure whose address is
placed in the tc_UserData field of the timer process's task
structure. A task that wishes to get access to this data need
only find the timer task (called 'MidiClock') and set a pointer
to the aforementioned structure (found in midiclock.h).
When midiclock is first invoked, an optional ticks/sec value
(default is 120) is read from the command line and the timer
process is started. Further invocations can be made to message
the running timer to either change its rate or terminate:
midiclock 240 changes the rate to 240 ticks/sec
midiclock -q terminates the timer
Next on the list of projects is to have the timer task send
wake-up messages (one-shot or continuous) to interested
tasks, typically for MIDI playback or sync. This is becoming
a sort of specialized timer.device, without a lot of the
overhead.
If you pass this source code on, please try to keep
'midiclock.h' with it.
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/tasks.h>
#include <exec/interrupts.h>
#include <hardware/cia.h>
#include <hardware/custom.h>
#include <hardware/intbits.h>
#include <resources/cia.h>
#include <stdio.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "midiclock.h"
extern struct CIA ciab;
struct mc_Msg *GetMsg();
static struct Interrupt
CIATimerInterrupt,
*OldCIAInterrupt = (struct Interrupt *)-1;
struct MidiClockData time;
static struct Library *CIAResource = NULL;
/* using CIAB timer B */
#define ciatlo ciab.ciatblo
#define ciathi ciab.ciatbhi
#define ciacr ciab.ciacrb
#define CIAINTBIT CIAICRB_TB
#define CLEAR 0
#define DEFAULT_TICKS 120
#define NOMSG -1
#define KILL 0
#define RATE 1
#define MC_PRIORITY 30
void CIAInterrupt()
{
time.counter++;
}
/* start the timer, clear pending interrupts, and enable timer B Interrupts */
StartCIATimer()
{
ciacr &= ~(CIACRBF_RUNMODE); /* set it to reload on overflow */
ciacr |= (CIACRBF_LOAD | CIACRBF_START);
SetICR(CIAResource,CLEAR|CIAICRF_TB);
AbleICR(CIAResource, CIAICRF_SETCLR | CIAICRF_TB);
return 0;
}
void StopCIATimer()
{
AbleICR(CIAResource, CLEAR | CIAICRF_TB);
ciacr &= ~CIACRBF_START;
}
void SetCIATimer (ticks) /* ticks/second converted to usecs */
int ticks;
{
long micros;
micros = (10000000 / ticks + 5) / 10;
time.intrvl = micros;
micros = (micros * 10000 / 1397 + 5) / 10; /* 1.397 usecs/tick */
ciatlo = micros & 0xff;
ciathi = micros >> 8;
}
void EndCIATimer()
{
if (OldCIAInterrupt == NULL)
{
StopCIATimer ();
RemICRVector (CIAResource, CIAINTBIT, &CIATimerInterrupt);
}
}
int BeginCIATimer (ticks)
int ticks;
{
/* Open the CIA resource */
if ((CIAResource = (struct Library *)OpenResource(CIABNAME)) == NULL)
{
return(1);
}
CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
CIATimerInterrupt.is_Node.ln_Pri = 127;
CIATimerInterrupt.is_Node.ln_Name = "CIA_MIDI_TIMER";
CIATimerInterrupt.is_Code = CIAInterrupt;
CIATimerInterrupt.is_Data = (APTR) &time;
/* install interrupt */
if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) != NULL)
{
EndCIATimer ();
return (2);
}
SetCIATimer (ticks);
StartCIATimer ();
return (0);
}
main (argc, argv)
int argc;
char *argv[];
{
int i, error, quit, ticks, oldpri;
char *pt, *oldname;
struct Process *FindTask(), *timerproc;
struct MsgPort *rpyport, *myport, *timerport, *CreatePort();
struct mc_Msg *msg, ctlmsg;
/* If timer process is not found, make this the timer process */
if ((timerproc = FindTask (MIDICLOCKNAME)) == NULL) {
if (argc > 1) ticks = atoi (argv[1]); /* command line arg */
else ticks = DEFAULT_TICKS;
if (error = BeginCIATimer (ticks)) { /* set up interrupt */
printf ("MIDICLOCK: error starting CIA timer.\n");
exit (error);
}
/* Set name and priority, hang clock's data structure on task
structure for access by other processes. */
timerproc = FindTask (0);
oldname = timerproc->pr_Task.tc_Node.ln_Name;
timerproc->pr_Task.tc_Node.ln_Name = MIDICLOCKNAME;
timerproc->pr_Task.tc_UserData = (APTR) &time;
oldpri = SetTaskPri (timerproc, MC_PRIORITY);
myport = &(timerproc->pr_MsgPort);
printf ("\nMIDICLOCK: started, rate is %d ticks/sec.\n", ticks);
for (quit = 0; !quit; ) {
WaitPort (myport); /* wait for control messages */
while (msg = GetMsg (myport)) {
switch (msg->command) {
case KILL:
quit = 1;
printf ("MIDICLOCK: terminated.\n");
break;
case RATE:
StopCIATimer ();
SetCIATimer (msg->data);
StartCIATimer ();
printf ("MIDICLOCK: rate is %d ticks/sec.\n", msg->data);
break;
default:
}
ReplyMsg (msg);
}
}
EndCIATimer (); /* stop timer and clear interrupt */
/* In the event that this process is attached to a CLI,
restore its name and priority */
timerproc->pr_Task.tc_Node.ln_Name = oldname;
SetTaskPri (timerproc, oldpri);
exit (0);
}
/* Timer process is already running, so this must be a control
job.
*/
if ((rpyport = CreatePort (0, 0)) == NULL) {
printf ("MIDICLOCK: Can't create reply port.\n");
goto cleanup;
}
ctlmsg.msg.mn_Node.ln_Type = NT_MESSAGE;
ctlmsg.msg.mn_ReplyPort = rpyport;
timerport = &(timerproc->pr_MsgPort);
/* process command line args, send control messages to timer */
for (i = 1; i < argc; i++) {
pt = argv[i];
if (*pt == '-') {
switch (*++pt) {
case 'q': /* terminate */
ctlmsg.command = KILL;
break;
case 't': /* change rate */
if (++i < argc) {
ctlmsg.command = RATE;
ctlmsg.data = atoi (argv[i]);
}
else ctlmsg.command = NOMSG;
break;
default:
}
}
else { /* non-switch argument is assumed to be time value */
ctlmsg.command = RATE;
ctlmsg.data = atoi (argv[i]);
}
if (ctlmsg.command != NOMSG) { /* send message, await reply */
PutMsg (timerport, &ctlmsg);
WaitPort (rpyport);
GetMsg (rpyport);
}
}
cleanup:
if (rpyport) DeletePort (rpyport);
return 0;
}